/*
更新日期：2017、02、14
作者：盛彬
备注信息：
原基础上需要较大幅度的修改了  把切割出来的画面投入学习还是全图是个问题
训练器生成xml后 这里直接导入文件启动对比识别
原始图像的预处理模块使用通用的方式


暂停ML开发
使用色像识别检测以快速出成品
估计识别出来后的再区分需要大改，主动剔除不好判断的

按照已有的指纹底色先做一个版本，也就是说图像识别这块暂停深入  处理上面走一段就好  那暂且继续把重点放在流媒体处理上面
看实际运行的效果 若需要还是把简易文字识别模块加进去
*/
#pragma once
#include "AllHeader.hpp"
#include "libLog.hpp"
#include "AVFramePP.hpp"
#include "AVPacketPP.hpp"
#include "SwsContextPP.hpp"
#include "libTestShow.hpp"

#ifndef libVideoParser2_H
#define libVideoParser2_H

const int sample_picture_num{ 8 }; //parser2中的原始素材图片数量
const int max_keep_rect{ 16 }; //一图片上所允许的最大可以区域数量

class VideoParserInfo
{
public:
    uint BufferMaxTime;// = 16  缓存时间  用这个设定缓存池总缓存时间
    uint Caption;// = 50   顶边栏高度
    uint Border;// = 50    底边栏高度
    uint WIDTH_DEN;// = 2     占屏宽比例分母
    uint HEIGHT_DEN;// = 3    占屏高比例分母
    uint Sampling;// = 2      取样频率分母
                  //
    int width;
    int height;
    Rect rec_pi;  //需要检测的图像部分

    int BaseColor1_RGB[3];
    // 模块常用的常量
    uint max_rect_width{ 0 }, max_rect_height{ 0 };
    uint max_rect_siz{ 0 };
};

class ParserBuffer :public libLog, public libTestShow
{
public:
    ~ParserBuffer()
    {
        if (src_buffer != nullptr)
        {
            delete[] src_buffer;
        }
        if (s_buffer != nullptr)
        {
            delete[] s_buffer;
        }
    }

    int InitParserBuffer(Size _size, enum AVPixelFormat _format_parserbuffer, enum AVPixelFormat _format_origin)
    {
        s_mat = _size;
        s_size = av_image_get_buffer_size(_format_parserbuffer, _size.width, _size.height, 1);
        s_buffer = new uint8_t[s_size];
        src_buffer_size = s_size*sample_picture_num;
        src_buffer = new uint8_t[src_buffer_size];
        if (!src_buffer)
        {
            return -1; //使用时注意返回值
        }

        sws_format2bgr.Init(s_mat.width, s_mat.height, _format_origin, s_mat.width, s_mat.height, _format_parserbuffer);

        uint8_t *p_buffer = src_buffer;
        for (int i = 0; i < sample_picture_num; i++)
        {
            src_array[i].create(Size(s_mat.width, s_mat.height), CV_8UC3); //统一 CV_8UC3
            src_array[i].data = p_buffer;
            p_buffer += s_size;
        }
        p_buffer = nullptr;
        return 0;
    }

    int AddFrame(AVFrame *_frame, int64_t _index)
    {
        if (src_buffer_m.try_lock())
        {
            if (NULL == _frame || _frame->data == NULL)
            {
                src_buffer_m.unlock();
                return -1;
            }
            //需要先转换一下
            AVFramePP framepp;
            framepp.InitSetFrame(AV_PIX_FMT_BGR24, _frame->width, _frame->height, s_buffer, s_size);

            sws_format2bgr.sws_scalePP(_frame, framepp.frame);

            memcpy(src_array[src_array_index].data, framepp.frame->data[0], s_size); //流媒体的缓存结构有变化  这里应该 也要变化才能实现兼容 重点在于兼容
            src_index[src_array_index] = _index;

            //        Test_Show(src_array_index, src_array[src_array_index]);
            //循环
            src_array_index++;
            if (src_array_index == sample_picture_num)
            {
                src_array_index = 0;
//                src_array_index_b = true;
            }
            src_buffer_m.unlock();
        }        
        return 0;
    }
    //
    Mat src_array[sample_picture_num];
    int64_t src_index[sample_picture_num];
    int src_array_index{ 0 }; //写入序号 上限 picture_num
//    bool src_array_index_b{ false }; //暂不使用

    Size s_mat;
    int s_size;
    uint8_t* s_buffer{ nullptr }; //Mat和AVFrame的内存结构上有一点差别 直接复制内存会导致显示异常 要么预处理要么手动设置内存结构并导入AVFrame里面去

    uint8_t *src_buffer{ nullptr }; //样本数据包  让Mat自动生成存放像素的内存似乎也可行···!!!!!!!!!!!!!!!!!!!!!!!!!! 初始时把内存都统一设置好 如; Mat xx(width,height,CV_8UC3,Scalar(0,0,255));
    uint32_t src_buffer_size{ 0 };
    mutex src_buffer_m;

    SwsContextPP sws_format2bgr;
};

class ParserPack2  //分析包结构   要改一下打码时的包信息读取方式，目前上一个包可能会导致下一个包无法及时把对应坐标对应上
{
public:
    vector<Rect> rec;

    int64_t max_index{ 0 };
    int64_t min_index{ 0 };
};

class libParserPack
{
public:
    int AddPP(ParserPack2 _pp) //注意变量传递是否安全 若需要改为&引用方式传递
    {
        if (0 == _pp.rec.size())
        {
            return -1;
        }
        m.lock();
        d_pp.push_back(_pp);
        m.unlock();
        return 0;
    }
    deque<ParserPack2> d_pp; //计算完成的分析包
    mutex m;
};

class libParser :public libLog, public libTestShow
{
public:
    libParser();//none
    ~libParser();//none
    int InitParser();

    VideoParserInfo PI; //直接保留一份数据到本地 
    ParserBuffer pbuffer; //内存
    libParserPack PP;
private:
    int Init();

    static void Thread_Parser2(void *p_this);
    void Thread_Parserr2();

    int MixPicture(Mat * _src_array, uint _number); //考虑融合这一步是否必须
    int AddWeighted_Mat(Mat *_src, Mat *_dst, int num); //8 4 2 1

    int RecognitionPicture(Mat _src, vector<Rect> &_rec);
    int StatisticsContour(vector<vector<Point>> &_contour, vector<Rect> &_rec);
    int CheckPixel(Mat _src, vector<Rect> &_rec);//检测像素值

    int AdjustDuration(ParserPack2 &_pp); //考虑直接设置为一旦发现，则设置一个目标index，在目标index前的图像坐标全部打码
public:
    bool b_thread_flag{ false };
    Mat src_blend;
    int64_t src_blend_index[sample_picture_num];
};


#endif //libVideoParser2_H